namespace OneWorks.Utils.FluentData
{
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Dynamic;

    internal class QueryHandler<TEntity>
    {
        private readonly DbCommandData _data;
        private readonly IQueryTypeHandler<TEntity> _typeHandler;

        public QueryHandler(DbCommandData data)
        {
            this._data = data;
            if (typeof(TEntity) == typeof(object) || typeof(TEntity) == typeof(ExpandoObject))
                this._typeHandler = new QueryDynamicHandler<TEntity>(data);
            else if (typeof(TEntity) == typeof(DataTable))
                this._typeHandler = new QueryDataTableHandler<TEntity>(data);
            else if (ReflectionHelper.IsCustomEntity<TEntity>())
                this._typeHandler = new QueryCustomEntityHandler<TEntity>(data);
            else
                this._typeHandler = new QueryScalarHandler<TEntity>(data);
        }

        internal TList ExecuteMany<TList>(Action<TEntity, IDataReader> customMapperReader,
                                          Action<TEntity, dynamic> customMapperDynamic
            )
            where TList : IList<TEntity>
        {
            var items = (TList)this._data.Context.Data.EntityFactory.Create(typeof(TList));
            var reader = this._data.Reader.InnerReader;
			
            if (this._typeHandler.IterateDataReader)
            {
                while (reader.Read())
                {
                    var item = (TEntity) this._typeHandler.HandleType(customMapperReader, customMapperDynamic);
                    items.Add(item);
                }
            }
            else
            {
                var item = (TEntity)this._typeHandler.HandleType(customMapperReader, customMapperDynamic);
                items.Add(item);
            }

            return items;
        }

        internal TEntity ExecuteSingle(Action<TEntity, IDataReader> customMapperReader,
                                       Action<TEntity, dynamic> customMapperDynamic)
        {
            var item = default(TEntity);
            if (!this._typeHandler.IterateDataReader || this._data.Reader.InnerReader.Read())
                item = (TEntity) this._typeHandler.HandleType(customMapperReader, customMapperDynamic);
				
            return item;
        }
    }
}